package cn.sourcespro.shiro.filter;

import cn.sourcespro.shiro.crudparams.vo.Vo;
import cn.sourcespro.shiro.util.SpringUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Set;

/**
 * security
 *
 * @author zhanghaowei
 * @date 2018/7/13
 */
public class CustomRolesAuthorizationFilter extends RolesAuthorizationFilter{

    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
        Subject subject = getSubject(request, response);
        String[] rolesArray = (String[]) mappedValue;
        //如果没有角色限制，直接放行
        if (rolesArray == null || rolesArray.length == 0) {
            return true;
        }

        Set<String> roles = CollectionUtils.asSet(rolesArray);
        return subject.hasAllRoles(roles);
    }

    @Override
    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        HttpServletRequest servletRequest = (HttpServletRequest) request;
        HttpServletResponse servletResponse = (HttpServletResponse) response;
        //处理跨域问题，跨域的请求首先会发一个options类型的请求
        if (servletRequest.getMethod().equals(HttpMethod.OPTIONS.name())) {
            return true;
        }
        boolean isAccess = isAccessAllowed(request, response, mappedValue);
        if (isAccess) {
            return true;
        }
        servletResponse.setCharacterEncoding("UTF-8");
        Subject subject = getSubject(request, response);
        PrintWriter printWriter = servletResponse.getWriter();
        servletResponse.setContentType("application/json;charset=UTF-8");
        servletResponse.setHeader("Access-Control-Allow-Origin", servletRequest.getHeader("Origin"));
        servletResponse.setHeader("Access-Control-Allow-Credentials", "true");
        servletResponse.setHeader("Vary", "Origin");
        ObjectMapper mapper = new ObjectMapper();
        String respStr;
        Session session = subject.getSession();
        RedisSessionDAO redisSessionDAO = (RedisSessionDAO) SpringUtil.getBean("redisSessionDAO");
        session = redisSessionDAO.readSession(session.getId());
        Boolean kickout = (Boolean) session.getAttribute("kickout");
        if (kickout != null && kickout) {
            respStr = mapper.writeValueAsString(new Vo("此账号已在其他设备登陆，请检查账号", HttpStatus.FORBIDDEN));
            DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
            DefaultWebSessionManager sessionManager = (DefaultWebSessionManager) securityManager.getSessionManager();
            sessionManager.getSessionDAO().delete(session);
        } else if (subject.getPrincipal() == null) {
            respStr = mapper.writeValueAsString(new Vo("您还未登录，请先登录", HttpStatus.FORBIDDEN));
        } else {
            respStr = mapper.writeValueAsString(new Vo("您没有此权限，请联系管理员", HttpStatus.FORBIDDEN));
        }
        printWriter.write(respStr);
        printWriter.flush();
        servletResponse.setHeader("content-Length", respStr.getBytes().length + "");
        return false;

    }
}
